package com.wwk.netty;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.nio.charset.Charset;
import java.util.Iterator;

/**
 * @Author wwk
 * @DATE 2022/5/24 13:48
 */
public class WriteClient {

    public static void main(String[] args) {
        try(//1.获得ServerSocketChannel连接
            ServerSocketChannel ssc = ServerSocketChannel.open()){
            //2.绑定端口,设置非阻塞
            ssc.bind(new InetSocketAddress(8080));
            ssc.configureBlocking(false);
            //3.获得selector
            Selector selector = Selector.open();
            //4.绑定channel，关注连接事件
            ssc.register(selector, SelectionKey.OP_ACCEPT);
            //持续监听事件
            while (true){
                selector.select(); //调用select
                //5.获取所有就绪事件的 key
                Iterator<SelectionKey> it = selector.selectedKeys().iterator();
                //遍历就绪事件
                while(it.hasNext()){
                    SelectionKey key = it.next();
                    // 处理后就移除事件
                    it.remove();
                    // 6. 根据key不同类型事件，处理
                    if(key.isAcceptable()){  //是连接事件
                        //获取客户端的连接通道
                        SocketChannel sc = ssc.accept();
                        // 写入数据
                        StringBuilder builder = new StringBuilder();
                        for(int i = 0; i < 80000000; i++) {
                            builder.append("a");
                        }
                        //封装数据
                        ByteBuffer byteBuffer = Charset.defaultCharset().encode(builder.toString());
                        // 先执行一次Buffer->Channel的写入，如果未写完，就添加一个可写事件
                        int write = sc.write(byteBuffer);
                        System.out.println(write);
                        //还有没写完的，通道中可能无法放入缓冲区中的所有数据,没写完会多次写入
                        if(byteBuffer.hasRemaining()){
                            //将channel注册到selector 中并关注写事件，并将buffer添加到key的附件中
                            sc.configureBlocking(false); //非阻塞
                            sc.register(selector,SelectionKey.OP_WRITE,byteBuffer);
                        }
                    }else if(key.isWritable()){// 是可写事件
                        //获得这个channel
                        SocketChannel sc = (SocketChannel)key.channel();
                        //获得没写完的 buffer
                        ByteBuffer byteBuffer = (ByteBuffer) key.attachment();
                        //再次写入
                        int write = sc.write(byteBuffer);
                        System.out.println(write);
                        //如果已经写完，清除这个
                        if(!byteBuffer.hasRemaining()){
                            // 如果已经完成了写操作，需要移除key中的附件，同时不再对写事件感兴趣
                            key.attach(null);
                            key.interestOps(0);
                        }
                    }

                }
            }

        }catch (IOException e){
            e.printStackTrace();
        }
    }
}
